package team.tttxs.ct.hibernate.dao.util;

import static org.springframework.data.mongodb.core.query.Criteria.where;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

public class DBHelper {

	/******* utility methods *******/
	public static Query buildSearchQuery(Map<String, Object> queryOptions) {
		Query query = new Query();
		if (queryOptions != null && !queryOptions.isEmpty()) {
			Criteria crit = new Criteria();
			for (String key : queryOptions.keySet()) {
				Object value = queryOptions.get(key);
				if (value instanceof String && ((String) value).startsWith("?")) {
					String strValue = (String) value;
					crit.and(key).regex(
							strValue.substring(1, strValue.length()));
				} else if (value instanceof List) {
					List listValue = (List) value;
					if (listValue.size() == 2
							&& ((listValue.get(0) instanceof Number && listValue
									.get(1) instanceof Number) || (listValue
									.get(0) instanceof Date && listValue.get(1) instanceof Date))) {
						crit.and(key).gte(listValue.get(0))
								.lte(listValue.get(1));
					} else {
						crit.and(key).in(listValue);
					}
				} else {
					crit.and(key).is(value);
				}
			}
			query.addCriteria(crit);
		}
		return query;
	}

	public static Query buildSearchQuery(Class clz,
			Map<String, Object> queryOptions) {

		Query query = new Query();
		if (queryOptions == null || queryOptions.isEmpty())
			return query;

		Criteria crit = new Criteria();
		for (String key : queryOptions.keySet()) {
			Object value = queryOptions.get(key);
			if (value instanceof String && ((String) value).startsWith("?")) {
				String strValue = (String) value;
				crit.and(key).regex(strValue.substring(1, strValue.length()));
			} else if (value instanceof List) {
				List listValue = (List) value;
				if (listValue.size() == 2
						&& ((listValue.get(0) instanceof Number && listValue
								.get(1) instanceof Number) || (listValue.get(0) instanceof Date && listValue
								.get(1) instanceof Date))) {

					Object opt1 = listValue.get(0);
					Object opt2 = listValue.get(1);

					if (listValue.get(0) instanceof Number
							&& listValue.get(1) instanceof Number
							&& DBHelper.isFieldTypeClass(clz, Date.class, key)) {

						opt1 = new Date(Long.valueOf(opt1.toString()));
						opt2 = new Date(Long.valueOf(opt2.toString()));
					}

					crit.and(key).gte(opt1).lte(opt2);

				} else {
					crit.and(key).in(listValue);
				}
			}else if (value instanceof String && ((String) value).startsWith("[")
					&& ((String) value).endsWith("]")) {

				String strValue = (String) value;
				String searchValue = strValue.substring(1,
						strValue.length() - 1);
				String[] searchValues = searchValue.split(",");

				if (searchValues != null && searchValues.length > 0) {
					Object op1=searchValues[0];
					Object op2=searchValues[1];
					
					Date d1=new Date(Long.parseLong(op1.toString()));
					Date d2=new Date(Long.parseLong(op2.toString()));
					
					crit.and(key).gte(d1).lte(d2);
				}
			} else if((value instanceof Long) || value.getClass().equals(Long.class)){
				crit.and(key).is(new Date(Long.parseLong(value.toString())));
			} else {
				crit.and(key).is(value);
			}			
		}
		query.addCriteria(crit);

		return query;
	}
	
	public static Query buildSearchQuery(Class clz,
			Map<String, Object> queryOptions, Query query) {

		if (queryOptions == null || queryOptions.isEmpty())
			return query;

		Criteria crit = new Criteria();
		for (String key : queryOptions.keySet()) {
			Object value = queryOptions.get(key);
			if (value instanceof String && ((String) value).startsWith("?")) {
				String strValue = (String) value;
				crit.and(key).regex(strValue.substring(1, strValue.length()));
			} else if (value instanceof List) {
				List listValue = (List) value;
				if (listValue.size() == 2
						&& ((listValue.get(0) instanceof Number && listValue
								.get(1) instanceof Number) || (listValue.get(0) instanceof Date && listValue
								.get(1) instanceof Date))) {

					Object opt1 = listValue.get(0);
					Object opt2 = listValue.get(1);

					if (listValue.get(0) instanceof Number
							&& listValue.get(1) instanceof Number
							&& DBHelper.isFieldTypeClass(clz, Date.class, key)) {

						opt1 = new Date(Long.valueOf(opt1.toString()));
						opt2 = new Date(Long.valueOf(opt2.toString()));
					}

					crit.and(key).gte(opt1).lte(opt2);

				} else {
					crit.and(key).in(listValue);
				}
			}else if (value instanceof String && ((String) value).startsWith("[")
					&& ((String) value).endsWith("]")) {

				String strValue = (String) value;
				String searchValue = strValue.substring(1,
						strValue.length() - 1);
				String[] searchValues = searchValue.split(",");

				if (searchValues != null && searchValues.length > 0) {
					Object op1=searchValues[0];
					Object op2=searchValues[1];
					
					Date d1=new Date(Long.parseLong(op1.toString()));
					Date d2=new Date(Long.parseLong(op2.toString()));
					
					crit.and(key).gte(d1).lte(d2);
				}
			} else {
				crit.and(key).is(value);
			}			
		}
		query.addCriteria(crit);

		return query;
	}

	public static void prepareQuery(Query query, Page page) {
		if (page == null) {
			// throw new
			// RuntimeException("page object is neccessary for query");
			return;
		}
		// default sort on updatedTime
		// query.sort().on("updatedTime", Order.DESCENDING);
		if (page.isSortable()) {
			for (String str : page.getOrderClauses().keySet()) {
				// query.sort().on(str, page.getOrderClauses().get(str));
				Integer direction = page.getOrderClauses().get(str);
				query.with(new Sort(direction <= 0 ? Sort.Direction.DESC
						: Sort.Direction.ASC, str));
			}
		}
		if (page.isRangeSupported()) {
			for (RangeCriteria rangeCrit : page.getRangeCriteria()) {
				if (rangeCrit.getOperator() == RangeCriteria.Operator.GT)
					query.addCriteria(where(rangeCrit.getAttribute()).gt(
							rangeCrit.getComparisonValue()));
				else
					query.addCriteria(where(rangeCrit.getAttribute()).lt(
							rangeCrit.getComparisonValue()));
			}
		} else {
			query.skip(page.getOffset());
		}

		if (page.getPagesize() >= 0) {
			query.limit(page.getPagesize());
		}
	}

	public static String getAnnotatedField(Class clz, Class annotationClz) {

		for (Field f : clz.getDeclaredFields()) {
			if (f.getAnnotation(annotationClz) != null) {
				return f.getName();
			}
		}
		return null;
	}

	public static boolean isFieldTypeClass(Class clz, Class typeClz, String key) {

		boolean bRtn = false;

		try {
			Field f = clz.getDeclaredField(key);
			bRtn = (f.getAnnotatedType().getType() == typeClz);

		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return bRtn;
	}

}
